<template>
  <el-card class="page_card">
    <div class="left_con">
      <el-input v-model="data.filterText" placeholder="请输入关键字搜索" />
      <el-tree 
        ref="treeRef" 
        highlight-current 
        default-expand-all 
        :data="data.toolTreeData" 
        node-key="categoryCode"
        :props="data.defaultProps"
        :filter-node-method="filterNode"
        :current-node-key="data.currentNodeKey"
        @node-click="handleNodeClick"/>
    </div>
    <div class="right_con">
      <el-form :inline="true" class="form">
        <el-form-item label="标题：">
          <el-input v-model="data.keyword" placeholder="请输入标题"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="Search" color="#626aef" @click="search" 
            :disabled="data.keyword?false:true">搜索</el-button>
          <el-button @click="reset" color="#626aef" plain>重置</el-button>
        </el-form-item>
      </el-form>
      <el-button type="primary" icon="Plus" @click="addRole">添加信息</el-button>
      <el-table border :data="data.infoTableData" row-key="id">
        <el-table-column label="序号" align="center" type="index" :width="100"></el-table-column>
        <el-table-column label="标题" align="left" header-align="center" prop="itemTitle"></el-table-column>
        <!-- <el-table-column label="内容" align="center">
          <template #default="scope"><span v-html="scope.row.content"></span></template>
        </el-table-column> -->
        <!-- <el-table-column label="缩略图" align="center" prop="thumbnail"></el-table-column> -->
        <el-table-column label="时间" align="center" :width="220">
          <template #default="scope">{{ scope.row.createTime }}</template>
        </el-table-column>
        <el-table-column label="操作" width="270px" align="center">
          <template #="{row}">
            <el-button type="primary" link icon="View" @click="viewOrUpdateRole(row,true)">查看</el-button>
            <el-button type="primary" link icon="Edit" @click="viewOrUpdateRole(row,false)">编辑</el-button>
            <el-popconfirm :title="`确认删除${row.itemTitle}吗？`" width="240px" 
              @confirm="deleteRole(row)">
              <template #reference>
                <el-button type="danger" link icon="Delete">删除</el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        v-model:current-page="data.currentPage"
        v-model:page-size="data.pageSize"
        :page-sizes="[10, 20, 30, 40]"
        :background="true"
        layout="->,prev, pager, next, jumper,sizes,total"
        :total="data.total"
        @current-change="currentChange"
        @size-change="sizeChange"
      />
    </div>
  </el-card>
  <!-- 添加信息、更新信息 -->
  <el-dialog v-model="data.addCategoryDialog" :title="data.infoForm.id?'更新信息':'添加信息'" width="1000" :align-center="true">
    <el-form :model="data.infoForm" :rules="data.rules" ref="formRef" label-width="100px" style="width: 930px">
      <el-form-item label="标题" prop="itemTitle">
        <el-input v-model="data.infoForm.itemTitle" placeholder="请输入标题"></el-input>
      </el-form-item>
      <el-form-item label="缩略图" prop="file">
        <el-upload
          class="avatar_uploader"
          action="#"
          :auto-upload="false"
          :show-file-list="false"
          :on-change="handleChange">
          <img v-if="data.fileImg" :src="data.fileImg" class="avatar" />
          <el-icon v-else class="avatar_uploader_icon"><Plus /></el-icon>
        </el-upload>
      </el-form-item>
      <el-form-item label="内容">
        <div style="border: 1px solid #dcdfe6">
          <Toolbar style="border-bottom: 1px solid #dcdfe6" :editor="editorRef" 
            :defaultConfig="toolbarConfig" mode="default"/>
          <Editor style="height: 350px; overflow-y: hidden" v-model="valueHtml" class="editor_con"
            :defaultConfig="editorConfig" mode="default" @onCreated="editorInit"/>
        </div>
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="data.addCategoryDialog = false">取消</el-button>
        <el-button type="primary" @click="save" :disabled="data.saveBtnDisabled">确定</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import {ref,onMounted,reactive,nextTick,watch,onUnmounted} from 'vue'
import {reqToolTreeData,reqGetDataByCategoryCode,reqAddOrUpdateInfo,reqRemoveInfo} from '@/api/expand/infoApi'
import type { Info,InfoResData } from '@/api/expand/infoType'
import { ElMessage } from 'element-plus'
import useLayOutSettingStore from '@/store/modules/setting'
import { ElTree } from 'element-plus'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { onBeforeUnmount, shallowRef } from 'vue'
import { reqGetImg,uploadFile } from '@/api/file/index'
import { blobToUrl } from '@/utils/file'

let settingStore = useLayOutSettingStore() // 模板setting仓库
let formRef = ref<any>() //form表单实例
const treeRef = ref<InstanceType<typeof ElTree>>()
const data = reactive({
  filterText:'',
  toolTreeData: [] as Array<any>, //工具树
  currentNodeKey: '',
  keyword:'',
  currentPage:1,
  pageSize:10,
  total:0,
  infoTableData:[] as Array<any>,
  addCategoryDialog:false, //新增对话框
  infoForm:{ //新增表单
    itemTitle:'', 
    thumbnail:'', //缩略图
    content:'', 
    categoryCode:'', //选中节点
    file:'',
    id: '',
    version:'',
  },
  defaultProps:{
    children: 'children',
    label: 'categoryName',
  },
  rules:{
    itemTitle:[{ required: true, trigger: 'blur', message:'请输入标题'}],
    // file:[{ required: true, trigger: 'blur', message:'请上传图片'}],
  },
  saveBtnDisabled:false,
  fileImg:'', //上传图片后回显
})

// 富文本编辑器
const editorRef = shallowRef()
const valueHtml = ref('')
// 工具栏和编辑栏 配置
const toolbarConfig = {
  //excludeKeys: []
  insertKeys: {
    index: 21, // 自定义插入的位置
    keys: ['uploadAttachment'], // “上传附件”菜单
  }
}
const editorConfig = { 
  placeholder: '请输入内容...',
  hoverbarKeys: {
    attachment: {
      menuKeys: ['downloadAttachment'], // “下载附件”菜单
    },
  },
  MENU_CONF: {
    uploadImage: {
      // 小于该值就插入 base64 格式（而不上传），默认为 0
      base64LimitSize: 5 * 1024, // 5kb
      // 单个文件的最大体积限制，默认为 2M
      // maxFileSize: 1 * 1024 * 1024, // 1M
      // // 最多可上传几个文件，默认为 100
      // maxNumberOfFiles: 5,
      // 选择文件时的类型限制，默认为 ['image/*'] 。如不想限制，则设置为 []
      allowedFileTypes: ['image/*'],
      async customUpload(file:any, insertFn:any) { // 文件上传
        try {
            const formData = new FormData();
            formData.append('file', file);
            let res= await uploadFile(formData);
            
            if (res) {
              insertFn(`/api/file/preview/${res}`,file.name,file.name);
            }else{
              ElMessage.error("图片上传失败");
            }
            
        } catch (e) {
          ElMessage.error("图片上传失败");
        }
         // 插入到富文本编辑器中，主意这里的三个参数都是必填的，要不然控制台报错：typeError: Cannot read properties of undefined (reading 'replace')
        // insertFn(result.data.data.url, result.data.data.name, result.data.data.name)
      }
    },
    uploadVideo:{
      async customUpload(file:any, insertFn:any) {
        try {
          const formData = new FormData();
          formData.append('file', file);
          let res= await uploadFile(formData);
          if (res) {
            insertFn(`/api/file/preview/${res}`,file.name,file.name);
          }else{
            ElMessage.error("视频上传失败");
          } 
        } catch (e) {
          ElMessage.error("视频上传失败");
        }
      }
    },
    uploadAttachment: {
      async customUpload(file: File, insertFn: Function) {
        let formData = new FormData();
        formData.append("file", file);
        let res= await uploadFile(formData);
        if (res) {
          insertFn(file.name,`/api/file/preview/${res}`);
        }else{
          ElMessage.error("附件上传失败");
          return;
        }
	    }
    }
  }
}
// 编辑器初始化完成时的回调函数
const editorInit = (editor:any) => {
  editorRef.value = editor // 记录 editor 实例，重要！
}
// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})

onMounted(() => {
  initTreeData()
})

watch( ()=> data.filterText, (val)=> {
  treeRef.value!.filter(val)
})

// 树节点搜索
const filterNode = (value: string, data: any) => {
  if (!value) return true
  return data.categoryName.includes(value)
}

// 工具树
const initTreeData = async () => {
  let res:any = await reqToolTreeData()
  if(res.code==200){
    data.toolTreeData = [
      {
        id:0,
        categoryName:'工具类别',
        categoryCode:'root_node',
        children:res.data.records
      }
    ]
    // 子节点默认勾选第一个
    data.currentNodeKey = res.data.records[0]?.categoryCode
    nextTick(() => {
      treeRef.value?.setCurrentKey(data.currentNodeKey)
      initTableData(data.currentNodeKey)
    })
  }
}

// 图片上传
const handleChange = (file:any) => {
  data.infoForm.file = file.raw //FormData格式图片
  const reader = new FileReader()
  reader.readAsDataURL(file.raw)
  reader.onload = (e) => {
    data.fileImg = (e.target?.result as string)
  }
}

// 搜索
const search = ()=>{
  initTableData()
}
// 重置
const reset = ()=>{
  settingStore.refsh = !settingStore.refsh
}
// 分页器下拉事件
const currentChange = () => {
  initTableData(data.currentNodeKey,data.currentPage)
}
const sizeChange = ()=> {
  initTableData()
}
// 点击树节点查询表格数据
const handleNodeClick = (nodeData: any) => {
  if(nodeData.categoryCode != 'root_node'){
    data.currentNodeKey = nodeData.categoryCode
    initTableData(data.currentNodeKey)
  }
}
// 根据工具categoryCode查询信息表格数据
const initTableData = async(categoryCode=data.currentNodeKey,pager=1)=> {
  data.currentPage = pager
  let params = {
    current:data.currentPage,
    size:data.pageSize,
    categoryCode:categoryCode,
    itemTitle:data.keyword
  }
  let res:InfoResData = await reqGetDataByCategoryCode(params)
  if(res.code==200){
    data.infoTableData = res.data.records
    data.total = res.data.total
  }
}
// 新增对话框
const addRole = ()=> {
  data.addCategoryDialog = true
  // 清空数据
  data.fileImg = ''
  valueHtml.value = '' //置空富文本编辑器
  Object.assign(data.infoForm,{
    itemTitle:'', 
    thumbnail:'', //缩略图
    content:'', 
    categoryCode:data.currentNodeKey, //选中节点
    file:'',
    id: '',
    version:'',
  })
  nextTick(() => {
    // 清除上一次错误提示信息
    formRef.value.clearValidate('itemTitle')
  })
}

onUnmounted(() => {
  if (data.fileImg) {  
    URL.revokeObjectURL(data.fileImg)
  } 
})

// 查看 / 编辑对话框
const viewOrUpdateRole = async(row:Info,disabled:boolean)=> {
  data.fileImg = ''
  // 根据文件名获取图片数据回显img
  let res = await reqGetImg(row.thumbnail)
  if (res) {
    // blob转url
    blobToUrl(res).then(dataUrl => {  
      data.fileImg = dataUrl
    }).catch(error => {ElMessage.error(error)})
  }
  // 富文本内容回显
  valueHtml.value = row.content
  data.saveBtnDisabled = disabled
  data.addCategoryDialog = true
  Object.assign(data.infoForm,row)
  nextTick(() => {
    // 清除上一次错误提示信息
    formRef.value.clearValidate('itemTitle')
  })
}
// 新增/编辑确认
const save = async() => {
  try{
    await formRef.value.validate()
    data.infoForm.content = valueHtml.value
    const formData = new FormData()
    const {file,id,categoryCode,itemTitle,content,version} = data.infoForm
    // 缩略图新增必填校验
    if(!id && !file){
      ElMessage.error('请上传缩略图！')
      return
    }
    const staticFields = {id,categoryCode,itemTitle,content,version}
    for(const [key, value] of Object.entries(staticFields)) {  
      formData.append(key, value)
    }
    if(file) {  
      formData.append('file', file) //上传文件处理
    }
    let res = await reqAddOrUpdateInfo(formData)
    if(res.code==200){
      data.addCategoryDialog = false
      ElMessage.success(data.infoForm.id?'更新成功！':'添加成功！')
      initTableData()
    }else{
      data.addCategoryDialog = false
      ElMessage.error(res.msg)
    }
  }catch (error) {}
}
// 删除单行角色
const deleteRole = async(row:Info)=>{
  let res = await reqRemoveInfo((row.id as number),row.version)
  if(res.code==200){
    ElMessage.success('删除成功！')
    initTableData()
  }else{
    ElMessage.error('删除失败！')
  }
}
</script>

<style scoped lang="scss">
:deep(.el-card__body) {
  display: flex;
  height: 100%;
  .left_con {
    width: 260px;
    height: 100%;
    border-right: 1px solid #dcdfe6;
    padding-right: 20px;
    .el-tree {
      margin-top: 14px;
    }
  }
  .right_con {
    flex: 1;
    height: 100%;
    padding-left: 20px;
  }
}
.avatar_uploader .avatar {
  width: 120px;
  height: 120px;
  display: block;
}
</style>

<style>
.avatar_uploader .el-upload {
  border: 1px dashed #dcdfe6;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}
.avatar_uploader .el-upload:hover {
  border-color: #626aef;
}
.el-icon.avatar_uploader_icon {
  font-size: 28px;
  color: #8c939d;
  width: 120px !important;
  height: 120px !important;
  text-align: center;
}
.editor_con{
  strong {
    font-weight: bold !important;
  }
  em {
    font-style: italic !important;
  }
}
</style>


